"""

Adder - Expression Parser

"""

from pyparsing import *
ParserElement.enablePackrat()
from ArithmeticParser import *
from VariableParser import *
import Bite
import Builtins
import sys

class ExpressionParser():
	def __init__(self, parent):
		self.engine = parent.engine # get access to the bytecode engine
		
		self.current_file = "<string>"
		self.current_line = -1
		
		self.variable = VariableParser(self);
		self.arithmetic = ArithmeticParser(self.variable, self);
		
		self.interpreter_indent_levels = [[0, "FILE"]]
		self.interpreter_indent_current_level = 0;
		self.interpreter_indent_last_command = ""
		self.interpreter_indent_last_expression = None
		self.interpreter_must_indent = False
		
		self.function_current_name = None
		
		self.import_allowed = True
	
	"""
	# Parses an expression.  Used by the main Adder file.
	"""
	def parseExpression(self, expression):
		# Store original expression for errors
		original_expression = expression.strip()
		
		# Check for a blank line or comment
		if (expression.strip() == "" or expression.startswith("#")):
			return ""
		
		buffer = ""
		
		# Check to see if the indentation has changed at all
		indent_amount = len(expression) - len(expression.lstrip())
		while (indent_amount < self.interpreter_indent_levels[self.interpreter_indent_current_level][0]):
			# We have moved out of an indentation level
			# Finish whatever mode we are currently in (e.g. IF, FUNCTION, EVENT, CLASS, etc..)
			mode = self.interpreter_indent_levels.pop()
			self.interpreter_indent_current_level -= 1;
			
			if (mode[1] == "FUNCTION" or mode[1] == "CONSTRUCTOR"):
				self.endFunction();
			if (mode[1] == "CLASS"):
				self.endClass();
			if (mode[1] == "IF"):
				# The if statement requires checking to see if the next expression
				# is an ELSE statement.
				if (expression.strip() == "else:" and indent_amount == self.interpreter_indent_levels[self.interpreter_indent_current_level][0]):
					# Else
					try:
						result = self.beginElse(mode[2]);
						return self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":else:\n") + self.storeByteCode(result);
					except:
						self.fatalError(expression, "Unexpected else statement.");
				else:
					# End if
					result = self.endIf(self.interpreter_indent_current_level + 1);
					buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "ELSE"):
				# End if
				result = self.endIf(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "WHILE"):
				result = self.endWhile(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "TRY"):
				# The try statement requires checking to see if the next expression
				# is an EXCEPT statement.
				if (expression.strip().startswith("except ") and indent_amount == self.interpreter_indent_levels[self.interpreter_indent_current_level][0]):
					# Except
					#try:
						result = self.beginExcept(expression);
						return self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":else:\n") + self.storeByteCode(result);
					#except:
					#	self.fatalError(expression, "Unexpected except statement.");
				else:
					# End Try
					result = self.endTry(self.interpreter_indent_current_level + 1);
					buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "EXCEPT"):
				# End Try
				result = self.endTry(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			
		if (indent_amount > self.interpreter_indent_levels[self.interpreter_indent_current_level][0]):
			# Check to make sure the indentation isn't out-of-order / there's no random indentation
			if (self.interpreter_indent_last_command == ""):
				self.fatalError(expression, "Unexpected indentation.");
		
			# We must be indenting on this line.  See what the previous command was (IF, FUNCTION, EVENT, etc.)
			if (self.interpreter_indent_last_expression == None):
				self.interpreter_indent_levels.append([indent_amount, self.interpreter_indent_last_command])
			else:
				self.interpreter_indent_levels.append([indent_amount, self.interpreter_indent_last_command, self.interpreter_indent_last_expression])
			self.interpreter_indent_current_level += 1
			self.interpreter_indent_last_command = ""
			self.interpreter_indent_last_expression = None
			self.interpreter_must_indent = False
		elif (indent_amount <= self.interpreter_indent_levels[self.interpreter_indent_current_level][0] and self.interpreter_must_indent):
			# The user needed to indent, but didn't.
			self.fatalError(expression, "Identation is required here (after start of " + self.interpreter_indent_last_command + " block).");
		
		# Now that we have dealt with indentation, we can strip the indentation
		expression = expression.strip();
		
		# SPECIAL: Check for print statement
		if (expression.startswith("print ")):
			# Function definition
			expression = "print(" + expression[6:].strip() + ")"
		
		# Check if imports are over.
		if (not expression.startswith("import ") and not expression.startswith("#") and expression != ""):
			# Imports no longer allowed.
			self.import_allowed = False
		
		# Perform the checks
		if (expression.startswith("import ")):
			# Import extension / other file
			if (self.import_allowed):
				buffer = self.bufferFix(buffer) + self.beginImport(expression);
			else:
				self.fatalError(expression, "All import statements must be before any other expressions.");
		elif (expression.startswith("def ")):
			# Function definition
			buffer = self.bufferFix(buffer) + self.beginFunction(expression);
		elif (expression.startswith("class ")):
			# Class definition
			buffer = self.bufferFix(buffer) + self.beginClass(expression);
		elif (expression.startswith("constructor(")):
			# Constructor definition
			buffer = self.bufferFix(buffer) + self.beginConstructor(expression);
		elif (expression.startswith("if ")):
			# If statement
			result = self.beginIf(expression);
			buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		elif (expression.startswith("while ")):
			# While statement
			result = self.beginWhile(expression);
			buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		elif (expression.startswith("return ")):
			# Return command
			result = self.returnExpression(expression);
			buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		elif (expression.startswith("pass ") or expression == "pass"):
			# Pass command (used for blank functions)
			if (expression.startswith("pass ")):
				# The pass call can not have any parameter
				self.fatalError(expression, "The 'pass' keyword can not have any appended parameters.");
			else:
				buffer += "";
		elif (expression.startswith("try ") or expression == "try:"):
			# Try statement
			if (expression.startswith("try ")):
				# The pass call can not have any parameter
				self.fatalError(expression, "The 'try' keyword can not have any parameters.");
			else:
				result = self.beginTry(expression);
				buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		elif (self.isAssignmentExpression(expression) and self.interpreter_indent_levels[self.interpreter_indent_current_level][1] != "CLASS"):
			# Assignment expression (not available in class block)
			result = self.assignmentExpression(expression);
			buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		elif (self.interpreter_indent_levels[self.interpreter_indent_current_level][1] != "CLASS"):
			# General expression (not available in class block)
			result = self.generalExpression(expression);
			
			# This has bytecode added to it that will clear the
			# mT0 register because it won't be used for assigning
			# the value of the register (which is done in the
			# assignment expressions where it is then cleared
			# by the VariableParser).
			result = result.strip() + "\nCLR mT0\n"
			
			buffer = self.bufferFix(buffer) + self.storeInterpreterReference(";" + self.current_file + ":" + str(self.current_line) + ":" + original_expression + "\n") + self.storeByteCode(result);
		else:
			# Error - try and predict what the user did wrong
			if (expression.startswith("constructor ")):
				self.fatalError(original_expression, "Class constructors can not be named.  The opening bracket must immediately follow the keyword.");
			else:
				self.fatalError(original_expression, "This type of expression can not be located inside a " + self.interpreter_indent_levels[self.interpreter_indent_current_level][1] + " block.");
		
		return buffer
	
	def bufferFix(self, buf):
		return buf.strip("\n") + "\n"
	
	"""
	# Finish off all of the indentation because we've reached
	# the end of the file.
	"""
	def finalizeIndentations(self):
		buffer = ""
		indent_amount = 0
		while (indent_amount < self.interpreter_indent_levels[self.interpreter_indent_current_level][0]):
			# We have moved out of an indentation level
			# Finish whatever mode we are currently in (e.g. IF, FUNCTION, EVENT, CLASS, etc..)
			mode = self.interpreter_indent_levels.pop()
			self.interpreter_indent_current_level -= 1;
			
			if (mode[1] == "FUNCTION" or mode[1] == "CONSTRUCTOR"):
				self.endFunction();
			if (mode[1] == "CLASS"):
				self.endClass();
			if (mode[1] == "IF"):
				# End if
				result = self.endIf(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "ELSE"):
				# End if
				result = self.endIf(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "WHILE"):
				result = self.endWhile(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "TRY"):
				# End Try
				result = self.endTry(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
			if (mode[1] == "EXCEPT"):
				# End Try
				result = self.endExcept(self.interpreter_indent_current_level + 1);
				buffer = self.bufferFix(buffer) + self.storeByteCode(result);
		
		return buffer
	
	"""
	# This function recieves bytecode, and depending on the current
	# indentation level and where we are at (e.g. an IF statement
	# or maybe a FUNCTION definition) will either store the bytecode
	# in one of the engine's dicts or hand it off to another function
	# in case of a conditional area.
	#
	# If the code should be added to the execute-right-now area, it will
	# simply return the bytecode handed to it.
	"""
	def storeByteCode(self, bytecode):
		l = self.interpreter_indent_current_level
		while (self.interpreter_indent_levels[l][1] != "FILE" and
			   self.interpreter_indent_levels[l][1] != "FUNCTION" and
			   self.interpreter_indent_levels[l][1] != "CONSTRUCTOR" and
			   l > 0):
			l -= 1
	
		m = self.interpreter_indent_levels[l][1]
		if (l != 0):
			u = self.interpreter_indent_levels[l - 1][1]
		else:
			u = [0, "INVALID"]
		if (m == "FILE"):
			# Execute-right-now
			return bytecode
		elif (m == "FUNCTION"):
			b = bytecode
			if (not b.endswith("\n") and b.strip() != ""): b += "\n"
			
			if (u == "FILE"):
				self.engine.functions[self.function_current_name].code += b
			elif (u == "CLASS"):
				self.engine.classes[self.class_name].functions[self.function_current_name].code += b
			else:
				self.fatalError("<no expression for this position>", "Unknown bytecode storage request for type " + m + " in block " + u + ".")
		elif (m == "CONSTRUCTOR"):
			b = bytecode
			if (not b.endswith("\n") and b.strip() != ""): b += "\n"
			
			if (u == "CLASS"):
				self.engine.classes[self.class_name].constructor.code += b
			else:
				self.fatalError("<no expression for this position>", "Unknown bytecode storage request for type " + m + " in block " + u + ".")
		
		return ""
	
	"""
	# This function recieves an interpreter line reference (for
	# errors, and depending on the current indentation level and
	# where we are at (e.g. maybe a FUNCTION definition) will
	# either store the bytecode in one of the engine's dicts or
	# hand it off to another function in case of a conditional area.
	#
	# If the reference should be added to the execute-right-now area,
	# it will simply return the bytecode handed to it.
	"""
	def storeInterpreterReference(self, reference):
		l = self.interpreter_indent_current_level
		while (self.interpreter_indent_levels[l][1] != "FILE" and
			   self.interpreter_indent_levels[l][1] != "FUNCTION" and
			   self.interpreter_indent_levels[l][1] != "CONSTRUCTOR" and
			   l > 0):
			l -= 1
	
		m = self.interpreter_indent_levels[l][1]
		if (l != 0):
			u = self.interpreter_indent_levels[l - 1][1]
		else:
			u = [0, "INVALID"]
		if (m == "FILE"):
			# Execute-right-now
			return reference
		elif (m == "FUNCTION"):
			b = reference
			if (not b.endswith("\n") and b.strip() != ""): b += "\n"
			
			if (u == "FILE"):
				self.engine.functions[self.function_current_name].code += b
			elif (u == "CLASS"):
				self.engine.classes[self.class_name].functions[self.function_current_name].code += b
			else:
				self.fatalError("<no expression for this position>", "Unknown interpreter reference storage request for type " + m + " in block " + u + ".")
		elif (m == "CONSTRUCTOR"):
			b = reference
			if (not b.endswith("\n") and b.strip() != ""): b += "\n"
			
			if (u == "CLASS"):
				self.engine.classes[self.class_name].constructor.code += b
			else:
				self.fatalError("<no expression for this position>", "Unknown interpreter reference storage request for type " + m + " in block " + u + ".")
		
		return ""
	
	"""
	# Handle an import statement
	"""
	def beginImport(self, expression):
		self.engine.imports.append(expression[len("import "):])
		return ""
	
	"""
	# Begins a try statement
	"""
	def beginTry(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		buf = """BERR catch""" + str(self.interpreter_indent_current_level) + """, catchRegister"""
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "TRY"
		self.interpreter_indent_last_expression = original_expression
		self.interpreter_must_indent = True
		
		return buf
	
	"""
	# Begins a except statement
	"""
	def beginExcept(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("except "):]
		
		buf = """BU except""" + str(self.interpreter_indent_current_level) + """
BRK catch""" + str(self.interpreter_indent_current_level) + """
DMOVV catchRegister, mT0
CLR catchRegister
""" + self.variable.parseExpression(expression, "=")
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "EXCEPT"
		self.interpreter_indent_last_expression = expression.strip()
		self.interpreter_must_indent = True
		
		return buf
	
	"""
	# Ends a try statement
	"""
	def endTry(self, level):
		# Generate the bytecode for the
		# end if
		buf = """BRK catch""" + str(level - 1) + """
BRK except""" + str(level - 1) + """
CLR catchRegister"""
		
		return buf
	
	"""
	# Ends a except statement
	"""
	def endExcept(self, level):
		# Generate the bytecode for the
		# end if
		buf = """BRK except""" + str(level - 1) + """
CLR catchRegister"""
		
		return buf
	
	"""
	# Begins an if statement
	"""
	def beginIf(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("if "):]
		
		# Generate the bytecode for the comparison
		bytecode = self.arithmetic.parseExpression(expression)
		
		buf = bytecode + """BF if""" + str(self.interpreter_indent_current_level) + """, mT0
CLR mT0"""
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "IF"
		self.interpreter_indent_last_expression = expression
		self.interpreter_must_indent = True
		
		return buf
	
	"""
	# Begins an else statement
	"""
	def beginElse(self, expression):
		# Original expression for errors
		original_expression = "else:"
		
		# Generate the bytecode for the comparison
		bytecode = self.arithmetic.parseExpression(expression)
		
		buf = bytecode + """
BRK if""" + str(self.interpreter_indent_current_level) + """
BT if""" + str(self.interpreter_indent_current_level) + """, mT0
CLR mT0"""
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "ELSE"
		self.interpreter_must_indent = True
		
		return buf
	
	"""
	# Ends an if statement
	"""
	def endIf(self, level):
		# Generate the bytecode for the
		# end if
		buf = """BRK if""" + str(level - 1) + """
CLR mT0"""
		
		return buf
	
	"""
	# Begins an while statement
	"""
	def beginWhile(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("while "):]
		
		# Generate the bytecode for the comparison
		bytecode = self.arithmetic.parseExpression(expression)
		
		buf = """LBL while""" + str(self.interpreter_indent_current_level) + """
""" + bytecode + """BF while""" + str(self.interpreter_indent_current_level) + """, mT0
CLR mT0"""
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "WHILE"
		self.interpreter_must_indent = True
		
		return buf
	
	"""
	# Ends an while statement
	"""
	def endWhile(self, level):
		# Generate the bytecode for the
		# end while
		buf = """JMPL while""" + str(level - 1) + """
BRK while""" + str(level - 1) + """
CLR mT0"""
		
		return buf
	
	"""
	# Begins a function definition
	"""
	def beginFunction(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("def "):]
		f = expression.partition("(")
		function_name = f[0]
		function_args = "(" + f[2]
		
		# Check to make sure that we are defining in a valid place.
		m = self.interpreter_indent_levels[self.interpreter_indent_current_level][1]
		if (not (m == "FILE" or m == "CLASS")):
			self.fatalError(original_expression, "Function '" + function_name + "' can not be defined inside a " + m + " block.");
		
		# Check to make sure function definition ends correctly
		if (function_args[-1] == ":"):
			function_args = function_args[:-1]
		else:
			self.fatalError(original_expression, "Function definition of '" + function_name + "' must end with ':' before code block.");
		
		# Check to make sure the arguments are formatted properly.
		self.function_current_arguments = list();
		if (len(function_args) == 0):
			# No arguments provided
			pass
		elif (function_args[0] == "(" and function_args[-1] == ")"):
			# Arguments provided, strip () and split by ,
			function_args = function_args.strip("()")
			function_args = function_args.split(",")
			for index, item in enumerate(function_args):
				function_args[index] = item.strip()
			
			if (len(function_args) == 1 and function_args[0].strip() == ""):
				function_args = list()
			
			self.function_current_arguments = function_args
		else:
			self.fatalError(original_expression, "Arguments of function '" + function_name + "' are incorrectly defined.");
		
		self.function_current_name = function_name;
		
		if (m == "FILE"):
			# Handle global scope
			if (self.function_current_name not in self.engine.functions and self.function_current_name not in self.engine.classes):
				self.engine.functions[self.function_current_name] = Bite.Func(self.function_current_name, self.function_current_arguments)
			else:
				self.fatalError(original_expression, "Function '" + self.function_current_name + "' is already defined in the global scope.")
		elif (m == "CLASS"):
			# Handle class scope
			if (self.class_name in self.engine.classes):
				self.engine.classes[self.class_name].functions[self.function_current_name] = Bite.Func(self.function_current_name, self.function_current_arguments)
				#
				# We used to have this if statement around the previous expression, but it conflicts
				# with class inheritance of functions.
				#
				#if (self.function_current_name not in self.engine.classes[self.class_name].functions):
				#else:
				#	self.fatalError(original_expression, "Function '" + self.function_current_name + "' is already defined in the scope of class '" + self.class_name + "'.")
			else:
				self.fatalError(original_expression, "Class '" + self.class_name + "' is not defined.")
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "FUNCTION"
		self.interpreter_must_indent = True
		
		return ""
	
	"""
	# Ends a function definition
	"""
	def endFunction(self):
		# debug write
		#f = open(self.function_current_name + ".Bite", "w")
		#if (self.class_name == None and self.function_current_name in self.engine.functions):
		#	f.write(self.engine.functions[self.function_current_name].code)
		#elif (self.class_name in self.engine.classes and self.function_current_name in self.engine.classes[self.class_name].functions):
		#	f.write(self.engine.classes[self.class_name].functions[self.function_current_name].code)
		#f.close()
	
		self.function_current_name = None
		self.function_current_arguments = None
		pass
	
	"""
	# Begins a class definition
	"""
	def beginClass(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("class "):]
		f = expression.partition("(")
		class_name = f[0]
		class_inheritance = "(" + f[2]
		
		# Check to make sure that we are defining in a valid place.
		m = self.interpreter_indent_levels[self.interpreter_indent_current_level][1]
		if (not m == "FILE"):
			self.fatalError(original_expression, "Class '" + class_name + "' can not be defined inside a " + m + " block.");
		
		# Check to make sure function definition ends correctly
		if (class_inheritance[-1] == ":"):
			class_inheritance = class_inheritance[:-1]
		else:
			self.fatalError(original_expression, "Class definition of '" + class_name + "' must end with ':' before class block.");
		
		# Check to make sure the inheritance is formatted properly.
		self.function_current_arguments = list();
		self.class_inheritance = None
		if (len(class_inheritance) == 0):
			# No arguments provided
			pass
		elif (class_inheritance[0] == "(" and class_inheritance[-1] == ")"):
			# Arguments provided, strip () and split by ,
			class_inheritance = class_inheritance.strip("()")
			if (class_inheritance.find(",") != -1 or class_inheritance.find('"') != -1):
				self.fatalError(original_expression, "Class inheritance of '" + class_inheritance + "' for '" + class_name + "' contains illegal characters.");
			
			self.class_inheritance = class_inheritance
		else:
			self.fatalError(original_expression, "Inheritance for '" + class_name + "' is incorrectly defined.");
		
		self.class_name = class_name;
		
		if (m == "FILE"):
			# Handle global scope
			if (self.class_name not in self.engine.classes and self.class_name not in self.engine.functions):
				if (self.class_inheritance != None and self.class_inheritance.strip() != ""):
					if (self.class_inheritance in self.engine.classes):
						self.engine.classes[self.class_name] = self.engine.classes[self.class_inheritance].clone()
						self.engine.classes[self.class_name].type = self.class_name
					else:
						self.fatalError(original_expression, "Inherited class '" + self.class_inheritance + "' was not found.  Inherited classes must be defined before subclasses.")
				else:
					self.engine.classes[self.class_name] = Bite.Obj(self.class_name)
				
				# Now we also need to define a global function for initializing the class.
				self.engine.functions[self.class_name] = Builtins.NewClassKW(self.class_name, list())
			else:
				self.fatalError(original_expression, "Class '" + self.class_name + "' is already defined in the global scope.")
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "CLASS"
		self.interpreter_must_indent = True
		
		return ""
	
	"""
	# Ends a class definition
	"""
	def endClass(self):
		self.class_name = None
		self.class_inheritance = None
		pass
	
	"""
	# Begins a class constructor definition
	"""
	def beginConstructor(self, expression):
		# Original expression for errors
		original_expression = expression.strip()
		
		# Get the function name out of the expression.
		expression = expression[len("constructor"):]
		function_args = expression
		
		# Check to make sure that we are defining in a valid place.
		m = self.interpreter_indent_levels[self.interpreter_indent_current_level][1]
		if (not m == "CLASS"):
			self.fatalError(original_expression, "Class constructors for can not be defined inside a " + m + " block.");
		
		# Check to make sure function definition ends correctly
		if (function_args[-1] == ":"):
			function_args = function_args[:-1]
		else:
			self.fatalError(original_expression, "Class constructor for '" + self.class_name + "' must end with ':' before code block.");
		
		# Check to make sure the arguments are formatted properly.
		self.function_current_arguments = list();
		if (len(function_args) == 0):
			# No arguments provided
			pass
		elif (function_args[0] == "(" and function_args[-1] == ")"):
			# Arguments provided, strip () and split by ,
			function_args = function_args.strip("()")
			function_args = function_args.split(",")
			for index, item in enumerate(function_args):
				function_args[index] = item.strip()
			
			if (len(function_args) == 1 and function_args[0].strip() == ""):
				function_args = list()
			
			self.function_current_arguments = function_args
		else:
			self.fatalError(original_expression, "Arguments of class constructor for '" + self.class_name + "' are incorrectly defined.");
		
		if (m == "CLASS"):
			# Handle class scope
			if (self.class_name in self.engine.classes):
				if (self.engine.classes[self.class_name].constructor == None):
					self.engine.classes[self.class_name].constructor = Bite.Func(self.function_current_name, self.function_current_arguments)
				else:
					self.fatalError(original_expression, "Class constructor for '" + self.class_name + "' is already defined.")
			else:
				self.fatalError(original_expression, "Class '" + self.class_name + "' is not defined.")
		
		# Finally, we set the new scope.
		self.interpreter_indent_last_command = "CONSTRUCTOR"
		self.interpreter_must_indent = True
		
		return ""
	
	"""
	# Determines whether it is an a = b expression
	"""
	def isAssignmentExpression(self, expression):
		primaryExpr = Forward()
		secondaryExpr = Forward()
		
		double = Word(nums + ".").setParseAction(lambda t:float(t[0]))
		integer = Word(nums).setParseAction(lambda t:int(t[0]))
		variable = Word(alphanums + "_")
		string = dblQuotedString
		funccall = Group(variable + "(" + Group(Optional(delimitedList(secondaryExpr))) + ")")
		array_func = Group(funccall + "[" + Group(delimitedList(secondaryExpr, "][", True)) + "]")
		array_var = Group(variable + "[" + Group(delimitedList(secondaryExpr, "][", True)) + "]")
		side = Combine(secondaryExpr, adjacent=False)
		
		primaryOperand = side
		secondaryOperand = double | string | array_func | funccall | array_var | variable

		equalityop = oneOf('== <= >= < > !=')
		assignmentop = oneOf('= += -= /= *=')
		expop = Literal('^')
		signop = oneOf('+ -')
		multop = oneOf('* /')
		plusop = oneOf('+ -')
		classop = Literal('.')
		
		# Secondary expressions (that is, inside brackets)
		# can use all of the operators.
		secondaryExpr << operatorPrecedence( secondaryOperand,
		[(equalityop, 2, opAssoc.LEFT),
			(classop, 2, opAssoc.LEFT),
			("^", 2, opAssoc.RIGHT),
			(signop, 1, opAssoc.RIGHT),
			(multop, 2, opAssoc.LEFT),
			(plusop, 2, opAssoc.LEFT),]
		)
		
		# The primary expression can only have the
		# class property operator
		primaryExpr << operatorPrecedence( primaryOperand,
		[(assignmentop, 2, opAssoc.LEFT)]
		)
		
		# Use pyParsing to interpret the expression
		try:
			result = primaryExpr.parseString(expression)
		except ParseException as e:
			error = str(e)
			self.fatalError(expression, "Unable to parse line.  Exact error: \n  " + error)
		
		try:
			if (isinstance(result[0], ParseResults)):
				if (result[0][1] == "=" or result[0][1] == "+=" or result[0][1] == "-=" or result[0][1] == "/=" or result[0][1] == "*="):
					self.assignment_cache_variable_name = result[0][0].strip()
					self.assignment_cache_assignment_operator = result[0][1].strip()
					self.assignment_cache_arithmetic_expression = result[0][2].strip()
					return True
			elif (result[1] == "=" or result[1] == "+=" or result[1] == "-=" or result[1] == "/=" or result[1] == "*="):
				self.assignment_cache_variable_name = result[0].strip()
				self.assignment_cache_assignment_operator = result[1].strip()
				self.assignment_cache_arithmetic_expression = result[2].strip()
				return True
			else:
				return False
		except:
			return False
		
		return False
	
	"""
	# Handles assignment "a = b" expressions.
	"""
	def assignmentExpression(self, expression):
		variable_name = self.assignment_cache_variable_name
		assignment_operator = self.assignment_cache_assignment_operator
		arithmetic_expression = self.assignment_cache_arithmetic_expression
		
		# Get the bytecode for the variable assignment
		bytecode_assign = self.variable.parseExpression(variable_name, assignment_operator)
		
		# Get the bytecode for the expression
		bytecode_expression = self.generalExpression(arithmetic_expression)
		
		# Put it together and return
		bytecode = bytecode_expression.strip() + "\n" + bytecode_assign.strip()
		
		return bytecode
	
	"""
	# Handles general "a" expressions.
	"""
	def generalExpression(self, expression):
		return self.arithmetic.parseExpression(expression, False).strip()
	
	"""
	# Handles return "return a" expressions.
	"""
	def returnExpression(self, expression):
		# The expression is a "return variable" expression.
		arithmetic_expression = expression[len("return "):]
		
		bytecode = self.arithmetic.parseExpression(arithmetic_expression, True).strip()
		bytecode += """
RET mT0
CLR mT0"""
		return bytecode
	
	"""
	# Throws a fatal error.
	"""
	def fatalError(self, code_text, error_text):
		print self.engine.before_error + """Traceback (most recent call last):
  File """ + '"' + self.current_file + '"' + """, line """ + str(self.current_line) + """
    """ + code_text + """

SyntaxError: """ + error_text
		sys.exit()